package com.skyd.core.android.game;

import java.util.Comparator;
import java.util.Date;
import java.util.Vector;
import java.util.concurrent.ConcurrentHashMap;

import com.skyd.core.android.game.GameObjectList.OnAddItemListener;
import com.skyd.core.android.game.GameObjectList.OnChangedListener;
import com.skyd.core.android.game.GameObjectList.OnRemoveItemListener;

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Bitmap.Config;

/**
 * 游戏场景，存放于游戏荧幕中，用于承载和管理精灵
 * 
 * @author SkyD
 * 
 */
public class GameScene extends GameRootObject implements ICurrentFrameNumberSupport {

	public GameScene() {
		_SpiritList.addOnAddItemListener(new OnAddItemListener<GameSpirit>() {

			@Override
			public void OnAddItemEvent(Object sender, GameSpirit newItem) {
				newItem
						.addOnLevelChangedListener(Spirit_OnLevelChangedListener);
			}
		});
		_SpiritList
				.addOnRemoveItemListener(new OnRemoveItemListener<GameSpirit>() {

					@Override
					public void OnRemoveItemEvent(Object sender,
							GameSpirit oldItem) {
						oldItem
								.removeOnLevelChangedListener(Spirit_OnLevelChangedListener);
					}
				});
		_SpiritList.addOnChangedListener(new OnChangedListener() {

			@Override
			public void OnChangedEvent(Object sender, int newSize) {
				sortSpiritList();
			}
		});
	}

	/**
	 * 初始值为new GameObjectList<GameSpirit>(this)。 功能注释：精灵列表
	 */
	private GameObjectList<GameSpirit> _SpiritList = new GameObjectList<GameSpirit>(
			this);

	/**
	 * 获取SpiritList。 功能注释：精灵列表
	 * 
	 * @return 当前的GameObjectList<GameSpirit>类型的值
	 */
	public GameObjectList<GameSpirit> getSpiritList() {
		return _SpiritList;
	}

	/**
	 * 设置SpiritList。 功能注释：精灵列表
	 * 
	 * @param value
	 *            要设置的GameObjectList<GameSpirit>类型值
	 */
	public void setSpiritList(GameObjectList<GameSpirit> value) {
		_SpiritList = value;
	}

	/**
	 * 设置SpiritList为其默认值(new GameObjectList<GameSpirit>(this))。 功能注释：精灵列表
	 */
	public void setSpiritListToDefault() {
		setSpiritList(new GameObjectList<GameSpirit>(this));
	}

	GameSpirit.OnLevelChangedListener Spirit_OnLevelChangedListener = new GameSpirit.OnLevelChangedListener() {
		@Override
		public void OnLevelChangedEvent(Object sender, float value) {
			sortSpiritList();
		}
	};

	/**
	 * 初始值为null。 功能注释：场景名称
	 */
	private String _Name = null;

	/**
	 * 获取Name。 功能注释：场景名称
	 * 
	 * @return 当前的String类型的值
	 */
	public String getName() {
		return _Name;
	}

	/**
	 * 设置Name。 功能注释：场景名称
	 * 
	 * @param value
	 *            要设置的String类型值
	 */
	public void setName(String value) {
		_Name = value;
	}

	/**
	 * 设置Name为其默认值(null)。 功能注释：场景名称
	 */
	public void setNameToDefault() {
		setName(null);
	}

	/**
	 * 根据名称获取场景中的精灵，同名的精灵将一并返回，如果不存在则返回空列表
	 * 
	 * @param name
	 *            精灵名称
	 * @return 精灵
	 */
	public Vector<GameSpirit> getSpiritsByName(String name) {
		Vector<GameSpirit> l = new Vector<GameSpirit>();
		for (GameSpirit f : _SpiritList) {
			if (f.getName() == name)
				l.add(f);
		}
		return l;
	}

	/**
	 * 根据精灵的图层顺序进行排序
	 */
	protected void sortSpiritList() {
		_SpiritList.sort(new Comparator<GameSpirit>() {

			@Override
			public int compare(GameSpirit arg0, GameSpirit arg1) {
				if (arg0.getLevel() == arg1.getLevel())
					return 0;
				else if (arg0.getLevel() > arg1.getLevel())
					return 1;
				else
					return -1;
			}
		});
	}

	/**
	 * 更新内部的精灵
	 */
	@Override
	public void updateChilds() {
		for (GameSpirit f : _SpiritList) {
			f.update();
		}
	}

	/**
	 * 绘制场景内部的精灵
	 */
	@Override
	protected void drawChilds(Canvas c, Rect drawArea) {
		int id = getTargetCacheID();
		if (id == 0) {
			normalDrawing(c,drawArea);
		} else {
			synchronized (_DrawCacheMap) {
				Bitmap bmp = null;
				try{
				bmp = getDrawCacheBitmap(id);
				Paint p = new Paint();
				if (bmp == null||bmp.getPixel(0, 0)==NeedsToRedrawColorSign) {
					if(new Date().getTime() - refreshTime<80){
						//如果要求刷新缓存，但时间间隔很小的话暂时忽略缓存直接输出，避免连续刷新时性能较差的情况
						normalDrawing(c,drawArea);
						return;
					}
					if(bmp==null)bmp = Bitmap.createBitmap(c.getWidth(), c.getHeight(),
							Config.RGB_565);
					Canvas bc = new Canvas(bmp);
					for (GameSpirit f : _SpiritList) {
						if (f.getLevel() <= _MaxDrawCacheLayer)
							drawChild(f,bc, drawArea);
					}
					// bc.save(Canvas.ALL_SAVE_FLAG);
					addDrawCacheBitmap(id, bmp);
				}
//				GameMaster.log(this, bmp.getPixel(0, 0));
				c.drawBitmap(bmp, 0, 0, p);
				}
				catch(Exception e){
					GameMaster.log(this, "绘制缓存失败，可能缓存对象已被释放");
					normalDrawing(c,drawArea);
					return;
				}
			}
			for (GameSpirit f : _SpiritList) {
				if (f.getLevel() > _MaxDrawCacheLayer)
					drawChild(f,c, drawArea);
			}
		}
	}

	/**
	 * 通常绘图方式，逐层绘制所有精灵
	 * @param c 画板
	 * @param drawArea 参考绘图区
	 */
	private void normalDrawing(Canvas c, Rect drawArea) {
		for (GameSpirit f : _SpiritList) {
			drawChild(f,c, drawArea);
		}
	}

	/**
	 * 添加到缓存图映射表
	 * 
	 * @param id
	 *            缓存ID
	 * @param bmp
	 *            缓存图
	 */
	private void addDrawCacheBitmap(int id, Bitmap bmp) {
		if (_DrawCacheMap.containsKey(id)) {
			_DrawCacheMap.remove(id);
		}
		_DrawCacheMap.put(id, bmp);
	}

	@Override
	protected void drawSelf(Canvas c, Rect drawArea) {

	}

	@Override
	protected void updateSelf() {
		_CurrentFrameNumber++;
	}

	/**
	 * 清除所有缓存图
	 */
	public void clearAllDrawCacheBitmap() {
		for (Integer f : _DrawCacheMap.keySet()) {
			clearDrawCacheBitmap(f);
		}
	}

	/**
	 * 清除指定ID以外的所有缓存图
	 * 
	 * @param CacheID
	 *            缓存ID
	 */
	public void clearAllDrawCacheBitmapWithout(int CacheID) {
		for (Integer f : _DrawCacheMap.keySet()) {
			if (f != CacheID)
				clearDrawCacheBitmap(f);
		}
	}

	/**
	 * 清除当前对应的之外的所有缓存图
	 */
	public void clearAllDrawCacheBitmapWithoutCurrent() {
		clearAllDrawCacheBitmapWithout(getTargetCacheID());
	}

	/**
	 * 清除当前对应的缓存图
	 */
	public void clearDrawCacheBitmap() {
		clearDrawCacheBitmap(getTargetCacheID());
	}
		
	/**
	 * 清除缓存图，仅当不再需要使用该缓存时执行以释放内存。如果仅需刷新，应执行refreshDrawCacheBitmap方法。
	 * 
	 * @param CacheID
	 *            缓存ID
	 */
	public void clearDrawCacheBitmap(int CacheID) {
		synchronized (_DrawCacheMap) {
			Bitmap b = getDrawCacheBitmap(CacheID);
			if (b != null) {
				_DrawCacheMap.remove(CacheID);
				b.recycle();
				b = null;
			}
		}
	}
	
	//当缓存图第一个(左上角)像素的颜色等于此值时表示缓存已过期，应当重绘
	final int NeedsToRedrawColorSign=-16244687;
	
	/**
	 * 刷新所有缓存图。此方法仅对缓存图做标记，在绘制时会根据此标记来执行重绘操作， 这样避免通过清除缓存的方式来刷新每次清除时都移除、回收、重建图像而产生内存占用超量问题
	 */
	public void refreshAllDrawCacheBitmap(){
		for (Integer f : _DrawCacheMap.keySet()) {
			refreshDrawCacheBitmap(f);
		}
	}
	
	/**
	 * 刷新除指定ID以外的所有缓存图。此方法仅对缓存图做标记，在绘制时会根据此标记来执行重绘操作， 这样避免通过清除缓存的方式来刷新每次清除时都移除、回收、重建图像而产生内存占用超量问题
	 */
	public void refreshAllDrawCacheBitmapWithout(int CacheID){
		for (Integer f : _DrawCacheMap.keySet()) {
			if (f != CacheID)
				refreshDrawCacheBitmap(f);
		}
	}
	
	/**
	 * 刷新除当前缓存图以外的所有缓存图。此方法仅对缓存图做标记，在绘制时会根据此标记来执行重绘操作， 这样避免通过清除缓存的方式来刷新每次清除时都移除、回收、重建图像而产生内存占用超量问题
	 */
	public void refreshAllDrawCacheBitmapWithoutCurrent(){
		refreshAllDrawCacheBitmapWithout(getTargetCacheID());
	}
	
	/**
	 * 刷新当前缓存图。此方法仅对缓存图做标记，在绘制时会根据此标记来执行重绘操作， 这样避免通过清除缓存的方式来刷新每次清除时都移除、回收、重建图像而产生内存占用超量问题
	 */
	public void refreshDrawCacheBitmap(){
		refreshDrawCacheBitmap(getTargetCacheID());
	}
	
	/**
	 * 刷新缓存图。此方法仅对缓存图做标记，在绘制时会根据此标记来执行重绘操作， 这样避免通过清除缓存的方式来刷新每次清除时都移除、回收、重建图像而产生内存占用超量问题
	 * @param CacheID 缓存ID
	 */
	public void refreshDrawCacheBitmap(int CacheID){
		Bitmap b = getDrawCacheBitmap(CacheID);
		if(b!=null){
			//在第一个(左上角)像素上做一个标记，表示需要重绘。
			refreshTime=new Date().getTime();
			b.setPixel(0, 0, NeedsToRedrawColorSign);
		}
	}
	
	/**
	 * 请求刷新的时间标记
	 */
	long refreshTime;

	/**
	 * 获取当前对应的缓存图
	 * 
	 * @return 缓存图
	 */
	public Bitmap getDrawCacheBitmap() {
		return getDrawCacheBitmap(getTargetCacheID());
	}

	/**
	 * 获取缓存图
	 * 
	 * @param CacheID
	 *            缓存ID
	 * @return 缓存图
	 */
	public Bitmap getDrawCacheBitmap(int CacheID) {
		if (_DrawCacheMap.containsKey(CacheID))
			return _DrawCacheMap.get(CacheID);
		else
			return null;
	}

	/**
	 * 初始值为new ConcurrentHashMap<Integer, Bitmap>()。 功能注释：场景状态缓存图映射表
	 */
	private ConcurrentHashMap<Integer, Bitmap> _DrawCacheMap = new ConcurrentHashMap<Integer, Bitmap>();

	/**
	 * 获取DrawCacheMap。 功能注释：场景状态缓存图映射表
	 * 
	 * @return 当前的ConcurrentHashMap<int,Bitmap>类型的值
	 */
	public ConcurrentHashMap<Integer, Bitmap> getDrawCacheMap() {
		return _DrawCacheMap;
	}

	/**
	 * 设置DrawCacheMap。 功能注释：场景状态缓存图映射表
	 * 
	 * @param value
	 *            要设置的ConcurrentHashMap<int,Bitmap>类型值
	 */
	public void setDrawCacheMap(ConcurrentHashMap<Integer, Bitmap> value) {
		_DrawCacheMap = value;
	}

	/**
	 * 设置DrawCacheMap为其默认值(new ConcurrentHashMap<Integer, Bitmap>())。 功能注释：场景状态缓存图映射表
	 */
	public void setDrawCacheMapToDefault() {
		setDrawCacheMap(new ConcurrentHashMap<Integer, Bitmap>());
	}

	/**
	 * 获取当前场景状态所对应的缓存ID，返回0则表示当前状态不需要缓存，此方法始终返回0，子类需要重新实现该方法以返回不同ID
	 * 
	 * @return 当前场景状态所对应的缓存ID
	 */
	public int getTargetCacheID() {
		return 0;
	}

	/**
	 * 初始值为0。 功能注释：缓存的最大层级，小于或等于此层级的精灵将被作为背景缓存
	 */
	private float _MaxDrawCacheLayer = 0;

	/**
	 * 获取MaxDrawCacheLayer。 功能注释：缓存的最大层级，小于或等于此层级的精灵将被作为背景缓存
	 * 
	 * @return 当前的float类型的值
	 */
	public float getMaxDrawCacheLayer() {
		return _MaxDrawCacheLayer;
	}

	/**
	 * 设置MaxDrawCacheLayer。 功能注释：缓存的最大层级，小于或等于此层级的精灵将被作为背景缓存
	 * 
	 * @param value
	 *            要设置的float类型值
	 */
	public void setMaxDrawCacheLayer(float value) {
		_MaxDrawCacheLayer = value;
	}

	/**
	 * 设置MaxDrawCacheLayer为其默认值(0)。 功能注释：缓存的最大层级，小于或等于此层级的精灵将被作为背景缓存
	 */
	public void setMaxDrawCacheLayerToDefault() {
		setMaxDrawCacheLayer(0);
	}
	
	/**
 * 初始值为0。
 * 功能注释：场景的当前帧计数
 */
	private  long _CurrentFrameNumber = 0;
/**
 * 获取CurrentFrameNumber。
 * 功能注释：场景的当前帧计数
 * @return 当前的long类型的值
 */
	public  long getCurrentFrameNumber() {
		return _CurrentFrameNumber;
	}
}
